package licence

import (
	"errors"
	"strconv"
)

type Categorys int

const (
	Category_B Categorys = iota
	Category_P
	Category_K
	Category_L
	Category_Y
	Category_R
)

func (c Categorys) String() string {
	switch c {
	case Category_B:
		return "B"
	case Category_P:
		return "P"
	case Category_K:
		return "K"
	case Category_L:
		return "L"
	case Category_Y:
		return "Y"
	case Category_R:
		return "R"
	default:
		return ""
	}
}

func GetCategory(c string) Categorys {
	switch c {
	case "B":
		// 骨髓(形态)
		return Category_B
	case "P":
		// 外周血(形态)
		return Category_P
	case "K":
		// 外周血(核型)
		return Category_K
	case "L":
		// 骨髓(核型)
		return Category_L
	case "Y":
		// 羊水(核型)
		return Category_Y
	case "R":
		// 骨髓R带(核型)
		return Category_R
	default:
		return Category_B
	}
}

const (
	// 保留位
	Reserve = "00"
)

/*
批次二维码、标签二维码

	B 0001 00 1 00 AB
	|    |  | |  |  +--- (2字节) 签名
	|    |  | |  +------ (2字节) 保留
	|    |  | +--------- (1字节) 限制次数
	|    |  +----------- (1字节) 编号 (每一批中实际最大的号做为这一批的批次码, 小于的做为标签码) (理论最大值: 1155)
	|    +-------------- (2字节) 批号 (最大值1336335)
	+------------------- (4字节) 类型 BPKLYR
*/
type QRCode struct {
	Category Categorys // 类型
	Batch    int       // 批号, 采用34进制 (占用4个字节) (0 ~ 1336335)
	No       int       // 编号, 采用34进制 (占用2个字节) (0 ~ 1155)
	UseTimes int       // 限制扫描的次数 (1个字节) 采用34进制 (0 ~ 33) (0:无限制)
}

func (qr QRCode) String(fixedCode string) string {
	return format(qr.Category.String() + str34(+qr.Batch, 4) + str34(qr.No, 2) + str34(qr.UseTimes, 1) + Reserve + qrCodeSignature(qr, fixedCode))
}

// 签名
func qrCodeSignature(qr QRCode, fixedCode string) string {
	fixedCode = format(fixedCode)
	code := qr.Category.String() + strconv.Itoa(qr.Batch) + strconv.Itoa(qr.No) + strconv.Itoa(qr.UseTimes) + fixedCode
	return format(signature(code, 2))
}

// 根据玻片批次码，批量生产二维码数据
func CreateQRCode(qr QRCode, fixedCode string) (batchCode string, qrCodeList []string, err error) {

	if qr.Batch < 1 || qr.Batch > 1336335 {
		err = errors.New("batch must > 0 and < 1336336")
		return
	}

	if qr.No < 1 || qr.No > 1155 {
		err = errors.New("no must > 1 and < 1156")
		return
	}

	if qr.UseTimes < 1 {
		qr.UseTimes = 0
	}

	if qr.UseTimes > 33 {
		qr.UseTimes = 33
	}

	// 批量生产二维码
	for i := 1; i < qr.No; i++ {
		qrCodeList = append(qrCodeList, QRCode{
			Category: qr.Category,
			Batch:    qr.Batch,
			No:       i,
			UseTimes: qr.UseTimes,
		}.String(fixedCode))
	}

	batchCode = qr.String(fixedCode)

	return
}

/*
检验标签码

	input:
		   qrcode: 标签码字符串
		fixedCode: 固定码
	output:
		status: 检验状态
		    qr: 标签码 (Struct: QRCode)
		   err: 异常状态信息
*/
func CheckQRCode(qrcode string, fixedCode string) (status bool, qr QRCode, err error) {

	// 检查长度
	if len(qrcode) != 12 {
		err = errors.New("the QR code length must be 12")
		return
	}

	// 固定码校验
	if len(fixedCode) == 0 {
		err = errors.New("fixed code cannot be empty")
		return
	}

	qr.Category = GetCategory(qrcode[0:1])
	qr.Batch = int34(qrcode[1:5])
	qr.No = int34(qrcode[5:7])
	qr.UseTimes = int34(qrcode[7:8])

	if qrcode[10:12] != qrCodeSignature(qr, fixedCode) {
		err = errors.New("this QRCode is invalid")
		return
	}

	status = true

	return
}
